package cn.snmp.mutual.uk.stack;


import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
public class TimeWindow {
    private static final String version_id = "@(#)$Id: TimeWindow.java,v 3.15 2007/04/12 12:55:28 birgita Exp $ Copyright Westhawk Ltd";
    public static final int MaxTimeDifference = 150;
    private static TimeWindow current;
    private Hashtable hostLookup;
    private Hashtable engineLookup;
    private long startTime;

    public TimeWindow() {
        if (TimeWindow.current == null) {
            TimeWindow.current = this;
            this.hostLookup = new Hashtable(5);
            this.engineLookup = new Hashtable(5);
        }
    }

    public static TimeWindow getCurrent() {
        return TimeWindow.current;
    }

    public String getSnmpEngineId(final String hostaddr, final int port) {
        final String key = this.getKey(hostaddr, port);
        final String snmpEngineId = (String) this.hostLookup.get(key);
        return snmpEngineId;
    }

    public boolean isSnmpEngineIdKnown(final String hostaddr, final int port) {
        final String key = this.getKey(hostaddr, port);
        return this.hostLookup.containsKey(key);
    }

    public void setSnmpEngineId(final String hostaddr, final int port, final String snmpEngineId) {
        final String key = this.getKey(hostaddr, port);
        if (AsnObject.debug > 4) {
            System.out.println();
            System.out.println(this.getClass().getName() + ".setSnmpEngineId(): hostaddr '" + hostaddr + "', port '" + port + "', snmpEngineId '" + snmpEngineId + "', key '" + key + "'");
        }
        this.hostLookup.put(key, snmpEngineId);
    }

    public boolean isEngineIdOK(final String hostaddr, final int port, final String snmpEngineId) {
        if (hostaddr.equals("127.0.0.1")) {
            return true;
        }
        boolean ok = true;
        final String key = this.getKey(hostaddr, port);
        if (!this.hostLookup.containsKey(key)) {
            this.setSnmpEngineId(hostaddr, port, snmpEngineId);
        } else {
            final String myEngineId = this.getSnmpEngineId(hostaddr, port);
            if (!myEngineId.equalsIgnoreCase(snmpEngineId)) {
                ok = false;
            }
        }
        if (AsnObject.debug > 4) {
            System.out.println();
            System.out.println(this.getClass().getName() + ".isEngineIdOK(): hostaddr '" + hostaddr + "', port '" + port + "', snmpEngineId '" + snmpEngineId + "', ok " + ok);
            log.info(".isEngineIdOK(): hostaddr '" + hostaddr + "', port '" + port + "', snmpEngineId '" + snmpEngineId + "', ok ");
        }
        return ok;
    }

    public boolean isTimeLineKnown(final String snmpEngineId) {
        return this.engineLookup.containsKey(snmpEngineId);
    }

    public boolean isOutsideTimeWindow(final String snmpEngineId, final int bootsA, final int timeA) {
        final boolean isOut = false;
        return isOut;
    }

    public boolean updateTimeWindow(final String snmpEngineId, final int bootsA, final int timeA, final boolean isAuthentic) {
        boolean updated = false;
        TimeWindowNode node = this.getTimeLine(snmpEngineId);
        if (node != null) {
            if (isAuthentic) {
                final int bootsL = node.getSnmpEngineBoots();
                final int latestL = node.getLatestReceivedEngineTime();
                if (bootsA > bootsL || (bootsA == bootsL && timeA > latestL)) {
                    synchronized (this) {
                        node.setSnmpEngineBoots(bootsA);
                        node.setSnmpEngineTime(timeA);
                        updated = true;
                    }
                }
            }
        } else if (bootsA > 0 || timeA > 0) {
            node = new TimeWindowNode(snmpEngineId, bootsA, timeA);
            this.setTimeLine(snmpEngineId, node);
        }
        if (AsnObject.debug > 4) {
            System.out.println();
            System.out.println(this.getClass().getName() + ".updateTimeWindow(): snmpEngineId '" + snmpEngineId + "', bootsA " + bootsA + ", timeA " + timeA + ", isAuthentic " + isAuthentic + ", updated " + updated);
        }
        return updated;
    }

    public void clearTimeWindow(final String snmpEngineId) {
        if (this.engineLookup.containsKey(snmpEngineId)) {
            this.engineLookup.remove(snmpEngineId);
            final Vector v = new Vector();
            for (Object key : this.hostLookup.keySet()) {
                if (this.hostLookup.get(key).equals(snmpEngineId)) {
                    v.add(key);
                }
            }
            final Iterator i = v.iterator();
            while (i.hasNext()) {
                this.hostLookup.remove(i.next());
            }
        }
    }

    protected void updateTimeWindows() {
        if (this.engineLookup.size() > 0) {
            final long now = System.currentTimeMillis();
            final long milli = now - this.startTime;
            final int sec = (int) (milli / 1000L);
            long lostMillis = milli - sec * 1000L;
            if (lostMillis < 0L) {
                lostMillis = 0L;
            }
            this.startTime = now - lostMillis;
            final Enumeration nodes = this.engineLookup.elements();
            while (nodes.hasMoreElements()) {
                final TimeWindowNode node = (TimeWindowNode) nodes.nextElement();
                node.incrementSnmpEngineTime(sec);
            }
        } else {
            this.startTime = System.currentTimeMillis();
        }
    }

    protected String getKey(final String hostaddr, final int port) {
        return hostaddr + ":" + port;
    }

    protected TimeWindowNode getTimeLine(final String snmpEngineId) {
        this.updateTimeWindows();
        final TimeWindowNode node = (TimeWindowNode) this.engineLookup.get(snmpEngineId);
        return node;
    }

    protected TimeWindowNode setTimeLine(final String snmpEngineId, final TimeWindowNode newNode) {
        this.updateTimeWindows();
        this.engineLookup.put(snmpEngineId, newNode);
        if (AsnObject.debug > 4) {
            System.out.println();
            System.out.println(this.getClass().getName() + ".setTimeLine(): snmpEngineId " + snmpEngineId + ", node " + newNode);
        }
        return newNode;
    }

    @Override
    public String toString() {
        final StringBuffer buffer = new StringBuffer(this.getClass().getName());
        buffer.append("[");
        final Enumeration enum1 = this.hostLookup.keys();
        while (enum1.hasMoreElements()) {
            final String key = (String) enum1.nextElement();
            final String snmpEngineId = (String) this.hostLookup.get(key);
            final TimeWindowNode node = (TimeWindowNode) this.engineLookup.get(snmpEngineId);
            buffer.append("\n\t(");
            if (node == null) {
                buffer.append("key=").append(key);
                buffer.append(", engineId=").append(snmpEngineId);
            } else {
                buffer.append("key=").append(key).append(", ");
                buffer.append(node.toString());
            }
            buffer.append(") ");
        }
        buffer.append("]");
        return buffer.toString();
    }

    static {
        TimeWindow.current = null;
    }
}
